﻿#include "FITKGraphObjectPredefinedFieldTemperature.h"

// VTK
#include <vtkPoints.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkProperty.h>
#include <vtkGlyph3D.h>
#include <vtkDistanceToCamera.h>
#include <vtkPointSource.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkIntArray.h>
#include <vtkDoubleArray.h>
#include <vtkExtractSelection.h>

// Graph
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"
#include "FITKGraphCommons.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKPolygonSource.h"

// Render
#include "FITK_Component/FITKRenderWindowVTK/FITKGraphRender.h"

// Data
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaPredefinedFieldTemperature.h"

// Data manager
#include "FITKSetSurfPolyProvider.h"

namespace Exchange
{
    FITKGraphObjectPredefinedFieldTemperature::FITKGraphObjectPredefinedFieldTemperature(AbaqusData::FITKDataCase* caseData, Interface::FITKAbaPredefinedFieldTemperature* fieldData)
        : FITKGraphObjectPredefinedFieldBase(caseData, fieldData)
    {
        if (!fieldData)
        {
            return;
        }

        // Initialize.
        init();

        // Generate the grid data.
        bool flag = generatePolyData(fieldData);
        if (!flag)
        {
            return;
        }

        // Generate tie actor.
        generateGraph();

        // Update the visibility.
        updateVisibility();
    }

    FITKGraphObjectPredefinedFieldTemperature::~FITKGraphObjectPredefinedFieldTemperature()
    {
        // Delete source.
//#ifdef QT_NO_DEBUG
        deleteVtkObj(m_polygonSource);
//#else
        deleteVtkObj(m_pointSource);
//#endif
    }

    void FITKGraphObjectPredefinedFieldTemperature::init()
    {
        this->Superclass::init();

        // Create source data.
//#ifdef QT_NO_DEBUG
        if (!m_simplifiedGlyph)
        {
            m_polygonSource = FITKPolygonSource::New();
            m_polygonSource->SetGeneratePolygon(false);
            m_polygonSource->SetGeneratePolyline(true);
            m_polygonSource->SetRadius(1);
            m_polygonSource->SetNumberOfSides(4);
        }
        else
        {
            m_pointSource = vtkPointSource::New();
        }
//#endif

        // Initialize the glyph size.
        m_glyphSize = 13.;
    }

    void FITKGraphObjectPredefinedFieldTemperature::initActors()
    {
        this->Superclass::initActors();

        // Get the field color .
        double color3[3] = { 0 ,0, 0 };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_tempFieldColor, color3);

        // Initialize actor properties.
        m_fActor->GetProperty()->SetColor(color3);
    }

    void FITKGraphObjectPredefinedFieldTemperature::highlight(QColor color)
    {
        // If the object is invisible, then return.
        if (!getDataVisibility())
        {
            return;
        }

        // Get the field highlight color.
        double color3[3] = { 0 ,0, 0 };
        if (color.isValid())
        {
            FITKGraphCommons::QColorToDouble3(color, color3);
        }
        else
        {
            FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_tempFieldHighlightColor, color3);
        }

        // Set the highlight color for glyph.
        if (m_fActor)
        {
            m_fActor->GetProperty()->SetColor(color3);
        }

        FITKGraphObject3D::highlight();
    }

    void FITKGraphObjectPredefinedFieldTemperature::disHighlight()
    {
        // Get the field default color.
        double color3[3] = { 0 ,0, 0 };
        FITKGraphCommons::QColorToDouble3(FITKGraphCommons::s_tempFieldColor, color3);

        // Set the default color for glyph.
        if (m_fActor)
        {
            m_fActor->GetProperty()->SetColor(color3);
        }     

        FITKGraphObject3D::disHighlight();
    }

    bool FITKGraphObjectPredefinedFieldTemperature::generatePolyData(Interface::FITKAbaAbstractPredefinedField* fieldData)
    {
        Interface::FITKAbaPredefinedFieldTemperature* tempField = dynamic_cast<Interface::FITKAbaPredefinedFieldTemperature*>(fieldData);
        if (!tempField)
        {
            return false;
        }

        // Generate location grid.
        bool flag = this->Superclass::generatePolyData(tempField);
        if (!flag)
        {
            return false;
        }

        // Add points for glyph.
        //@{
        // Get the model id array of location.
        for (int j = 0; j < m_gridLoc->GetNumberOfPoints(); j++)
        {
            int modelId = -1;
            if (m_modelIdArrayLoc)
            {
                modelId = m_modelIdArrayLoc->GetValue(j);
            }

            // Add a point and a cell.
            //@{
            // Add point.
            int ptId = m_points->InsertNextPoint(m_gridLoc->GetPoint(j));

            // Add cell.
            vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
            cell->InsertNextId(ptId);
            m_ugrid->InsertNextCell(VTKCellType::VTK_VERTEX, cell);

            // Add model id and normal.
            m_modelIdArray->InsertNextValue(modelId);
            //@}
        }

        return true;
    }
    
    void FITKGraphObjectPredefinedFieldTemperature::generateGraph()
    {
        if (!m_ugrid)
        {
            return;
        }

        // Create actors.
        initActors();

        // Create the glyph filter.
        vtkGlyph3D* glyph = vtkGlyph3D::New();
        glyph->SetScaling(true);
        glyph->SetScaleModeToScaleByScalar();
        glyph->SetVectorModeToVectorRotationOff();

        // Add to data list.
        m_glyphList.push_back(glyph);

        m_fActor->setInputConnection(glyph->GetOutputPort());

//#ifdef QT_NO_DEBUG
        if (!m_simplifiedGlyph)
        {
            m_fActor->GetProperty()->SetLineWidth(1);

            m_extractSelection->SetInputData(m_ugrid);

            vtkDistanceToCamera* distanceToCamera = vtkDistanceToCamera::New();
            distanceToCamera->SetScreenSize(m_glyphSize);

            // Set the input.
            distanceToCamera->SetInputConnection(m_extractSelection->GetOutputPort());

            // Add the point array name need to be used.             
#if VTK_MAJOR_VERSION < 8
            glyph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "DistanceToCamera");
#else
            glyph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, distanceToCamera->GetDistanceArrayName());
#endif

            glyph->SetInputConnection(distanceToCamera->GetOutputPort());

            // Add to data list.
            m_distToCameraList.push_back(distanceToCamera);

            // Set the soure data and input data.
            glyph->SetSourceConnection(m_polygonSource->GetOutputPort());
            //@}
        }
        else
        {
            m_fActor->GetProperty()->SetPointSize(m_glyphSize);

            // Set the input connection for glyph.
            glyph->SetInputConnection(m_extractSelection->GetOutputPort());

            // Set the soure data and input connection.
            glyph->SetSourceConnection(m_pointSource->GetOutputPort());
        }
//#endif // QT_NO_DEBUG
    }

    void FITKGraphObjectPredefinedFieldTemperature::setFITKRender(Comp::FITKGraphRender* render)
    {
        if (!render)
        {
            return;
        }

        vtkRenderer* renderer = render->getRenderer();
        if (!renderer)
        {
            return;
        }

        // Set the renderer for calculating size.
        for (vtkDistanceToCamera* obj : m_distToCameraList)
        {
            if (obj)
            {
                obj->SetRenderer(renderer);
            }
        }

        // Initialize the normal.
        updateCameraNormal();

        // Save the render.
        this->Superclass::setFITKRender(render);
    }

    void FITKGraphObjectPredefinedFieldTemperature::updateCameraNormal()
    {
//#ifdef QT_NO_DEBUG
        if (!m_simplifiedGlyph && m_fRender)
        {
            vtkRenderer* renderer = m_fRender->getRenderer();
            if (!renderer || !m_polygonSource)
            {
                return;
            }

            vtkCamera* camera = renderer->GetActiveCamera();
            if (camera)
            {
                m_polygonSource->SetNormal(camera->GetViewPlaneNormal());
            }
        }
//#endif
    }
}   // namespace Exchange